package com.ruoyi.common.utils;


import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT Token工具类，用于生成和验证登录Token
 */
public class JwtLongTokenUtil {
    // 单例实例
    private static volatile JwtLongTokenUtil instance;

    // Token过期时间(毫秒)，这里设置为24小时
    private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000;

    // 密钥，实际应用中应该从配置文件或环境变量中获取
    private static final String SECRET = "your-secret-key";

    // 算法实例
    private final Algorithm algorithm;

    // 验证器实例
    private final JWTVerifier verifier;

    /**
     * 私有构造方法，初始化算法和验证器
     */
    private JwtLongTokenUtil() {
        try {
            algorithm = Algorithm.HMAC256(SECRET);
            verifier = JWT.require(algorithm).build();
        } catch (Exception e) {
            throw new RuntimeException("初始化JWT工具类失败", e);
        }
    }

    /**
     * 获取单例实例
     *
     * @return JwtTokenUtil实例
     */
    public static JwtLongTokenUtil getInstance() {
        if (instance == null) {
            synchronized (JwtLongTokenUtil.class) {
                if (instance == null) {
                    instance = new JwtLongTokenUtil();
                }
            }
        }
        return instance;
    }

    /**
     * 生成Token
     *
     * @param userId   用户ID
     * @param username 用户名
     * @return 生成的Token字符串
     * @throws JWTCreationException 当生成Token失败时抛出
     */
    public String generateToken(String userId, String username) throws JWTCreationException {
        Date now = new Date();
        Date expireDate = new Date(now.getTime() + EXPIRE_TIME);

        return JWT.create()
                .withIssuer("auth0")  // 发行人
                .withClaim("userId", userId)  // 自定义用户ID声明
                .withClaim("username", username)  // 自定义用户名声明
                .withIssuedAt(now)  // 发行时间
                .withExpiresAt(expireDate)  // 过期时间
                .sign(algorithm);  // 使用算法签名
    }

    /**
     * 生成带自定义声明的Token
     *
     * @param claims 自定义声明
     * @return 生成的Token字符串
     * @throws JWTCreationException 当生成Token失败时抛出
     */
    public String generateTokenWithClaims(Map<String, Object> claims) throws JWTCreationException {
        Date now = new Date();
        Date expireDate = new Date(now.getTime() + EXPIRE_TIME);

        JWTCreator.Builder builder = JWT.create()
                .withIssuer("auth0")
                .withIssuedAt(now)
                .withExpiresAt(expireDate);

        // 添加自定义声明
        if (claims != null && !claims.isEmpty()) {
            for (Map.Entry<String, Object> entry : claims.entrySet()) {
                builder.withClaim(entry.getKey(), entry.getValue().toString());
            }
        }

        return builder.sign(algorithm);
    }

    /**
     * 验证Token并返回解码后的JWT
     *
     * @param token 待验证的Token
     * @return 解码后的JWT
     * @throws JWTVerificationException 当验证失败时抛出
     */
    public DecodedJWT verifyToken(String token) throws JWTVerificationException {
        return verifier.verify(token);
    }

    /**
     * 从Token中获取用户ID
     *
     * @param token Token字符串
     * @return 用户ID
     * @throws JWTVerificationException 当验证失败时抛出
     */
    public String getUserId(String token) throws JWTVerificationException {
        DecodedJWT jwt = verifyToken(token);
        return jwt.getClaim("userId").asString();
    }

    /**
     * 从Token中获取用户名
     *
     * @param token Token字符串
     * @return 用户名
     * @throws JWTVerificationException 当验证失败时抛出
     */
    public String getUsername(String token) throws JWTVerificationException {
        DecodedJWT jwt = verifyToken(token);
        return jwt.getClaim("username").asString();
    }

    /**
     * 从Token中获取所有声明
     *
     * @param token Token字符串
     * @return 声明的Map
     * @throws JWTVerificationException 当验证失败时抛出
     */
    public Map<String, Claim> getClaims(String token) throws JWTVerificationException {
        DecodedJWT jwt = verifyToken(token);
        return jwt.getClaims();
    }

    /**
     * 检查Token是否过期
     *
     * @param token Token字符串
     * @return 如果过期返回true，否则返回false
     * @throws JWTVerificationException 当验证失败时抛出
     */
    public boolean isTokenExpired(String token) throws JWTVerificationException {
        DecodedJWT jwt = verifyToken(token);
        return jwt.getExpiresAt().before(new Date());
    }

    /**
     * main方法用于演示JwtTokenUtil的使用示例
     */
    public static void main(String[] args) {
        try {
            // 1. 获取工具类实例
            JwtLongTokenUtil jwtUtil = JwtLongTokenUtil.getInstance();
            System.out.println("=== JwtTokenUtil使用示例 ===");

            // 2. 演示1: 生成基础Token并验证
            System.out.println("\n----- 基础Token演示 -----");
            String userId = "user123";
            String username = "testUser";
            String basicToken = jwtUtil.generateToken(userId, username);
            System.out.println("生成基础Token: " + basicToken);

            // 验证Token并提取信息
            DecodedJWT basicJwt = jwtUtil.verifyToken(basicToken);
            System.out.println("验证成功 - 用户ID: " + jwtUtil.getUserId(basicToken));
            System.out.println("验证成功 - 用户名: " + jwtUtil.getUsername(basicToken));
            System.out.println("Token是否过期: " + jwtUtil.isTokenExpired(basicToken));

            // 3. 演示2: 生成带自定义声明的Token
            System.out.println("\n----- 带自定义声明的Token演示 -----");
            Map<String, Object> customClaims = new HashMap<>();
            customClaims.put("role", "admin");
            customClaims.put("dept", "技术部");
            customClaims.put("isVip", true);
            String customToken = jwtUtil.generateTokenWithClaims(customClaims);
            System.out.println("生成带自定义声明的Token: " + customToken);

            // 提取自定义声明
            DecodedJWT customJwt = jwtUtil.verifyToken(customToken);
            Map<String, Claim> claims = jwtUtil.getClaims(customToken);
            System.out.println("提取自定义声明 - 角色: " + claims.get("role").asString());
            System.out.println("提取自定义声明 - 部门: " + claims.get("dept").asString());
            System.out.println("提取自定义声明 - 是否VIP: " + claims.get("isVip").asBoolean());

            // 4. 演示3: 验证无效Token（预期会失败）
            System.out.println("\n----- 无效Token验证演示 -----");
            String invalidToken = "invalid.token.here";
            jwtUtil.verifyToken(invalidToken); // 此行会抛出异常

        } catch (JWTCreationException e) {
            System.err.println("Token生成失败: " + e.getMessage());
        } catch (JWTVerificationException e) {
            System.err.println("Token验证失败: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("其他错误: " + e.getMessage());
        }
    }

}